/*
 * canttchartscene.cpp
 * 甘特图场景实现文件
 * 实现CanttChartScene类的成员函数，负责管理时间轴、网格线和时间条项
 */
#include "canttchartscene.h"
#include "definition.h"
#include "cantttimebaritem.h"

#include <QBrush>
#include <QPen>
#include <QGraphicsLineItem>
#include <QGraphicsTextItem>
#include <QDebug>
#include <QCheckBox>
#include <QGraphicsProxyWidget>
#include <QCursor>

// 水平网格第一个宽度
const int firstHorizantalGridWidth = 100;
// 水平网格宽度
const int horizontalGridWidth = 40;
// 垂直网格高度
const int verticalGridHeight = 40;
// 水平轴文本高度
const int horizontalAxisTextHeight = 21;
// 水平轴文本偏移
const int horizontalAxisTextOffset = 5;
// 轴起始点
const QPoint axisStartPoint = QPoint(20, 40);
// 平台标题偏移
const QPoint platformHeaderOffset = QPoint(6, 10);
// 网格线颜色
const QColor gridLineColor = QColor(48, 85, 93);
// 日期刻度颜色
const QColor scaleDateColor = QColor(253, 201, 115);
// 时间刻度颜色
const QColor scaleTimeColor = QColor(208, 216, 237);

/**
 * @brief CanttChartScene类的构造函数
 * @param parent 父对象指针
 * @details 初始化甘特图场景，设置背景颜色和时间像素转换因子
 */
CanttChartScene::CanttChartScene(QObject *parent) : QGraphicsScene(parent),
    m_rowCount(0), m_columnCount(0), m_stepTimeValue(0, 30)
{
    // 设置背景颜色
    setBackgroundBrush(QBrush(QColor(43, 48, 54)));

    // 计算每像素对应的毫秒数
    m_perPixelHMsecs =  m_stepTimeValue.msecsSinceStartOfDay() / (double)horizontalGridWidth;
}

/**
 * @brief 设置时间轴范围
 * @param start 开始时间
 * @param end 结束时间
 * @param platforms 平台列表
 * @details 配置时间轴范围和平台，清空现有图形项，绘制坐标轴和网格线
 */
void CanttChartScene::setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms)
{
    // 检查参数有效性
    if (start >= end || 0 == platforms.count())
    {
        return;
    }

    // 更新成员变量
    m_rowCount = platforms.count();
    m_startDateTime = start;
    m_endDateTime = end;
    m_platforms = platforms;
    m_firstTimeBarStartX = axisStartPoint.x() + firstHorizantalGridWidth;
    m_firstTimeBarStartY = axisStartPoint.y();

    // 清空现有图形项
    clear();

    // 绘制前先预留足够空间
    double sceneMiniWidth = m_firstTimeBarStartX + horizontalGridWidth
            + (end.toMSecsSinceEpoch() - start.toMSecsSinceEpoch()) / m_perPixelHMsecs;
    double sceneMiniHeight = m_firstTimeBarStartY + platforms.count() * verticalGridHeight;

    // 设置场景矩形
    setSceneRect(0, 0, sceneMiniWidth, sceneMiniHeight + 800);

    // 绘制垂直坐标轴
    drawVerticalAxis(platforms);

    // 初始化时间变量
    QDateTime startDateTime = start;
    QDate startDate = start.date();

    // 绘制水平时间轴和刻度
    double x = m_firstTimeBarStartX;
    for (; x <= sceneMiniWidth; x += horizontalGridWidth)
    {
        // 创建时间文本项
        QGraphicsTextItem *timeItem = new QGraphicsTextItem(startDateTime.toString("hh:mm"));
        timeItem->setDefaultTextColor(scaleTimeColor);
        timeItem->setZValue(std::numeric_limits<int>::min());
        timeItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight);
        addItem(timeItem);

        // 绘制第一个日期文本
        if (x == axisStartPoint.x() + firstHorizantalGridWidth)
        {
            QGraphicsTextItem *dateItem = new QGraphicsTextItem(startDateTime.date().toString("yyyy-MM-dd"));
            dateItem->setDefaultTextColor(scaleDateColor);
            dateItem->setZValue(std::numeric_limits<int>::min());
            addItem(dateItem);
            dateItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight*2);
        }
        else
        {
            // 绘制后续日期文本（日期变化时）
            if (startDateTime.date() > startDate)
            {
                QGraphicsTextItem *dateItem = new QGraphicsTextItem(startDateTime.date().toString("yyyy-MM-dd"));
                dateItem->setDefaultTextColor(scaleDateColor);
                dateItem->setZValue(std::numeric_limits<int>::min());
                addItem(dateItem);
                dateItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight*2);
                startDate = startDateTime.date();
            }
        }

        // 增加时间步长
        startDateTime = startDateTime.addMSecs(m_stepTimeValue.msecsSinceStartOfDay());

        // 增加列数
        m_columnCount++;

        // 防止无限循环
        if (startDateTime > QDateTime::currentDateTime())
        {
            break;
        }
    }

    // 绘制网格线
    drawGridLines();

    // 扩展场景矩形
    QRectF rect = this->sceneRect();
    setSceneRect(0, 0, rect.width() + 200, rect.height() + 200);
}

/**
 * @brief 绘制垂直坐标轴
 * @param platforms 平台列表
 * @details 为每个平台绘制垂直坐标轴和复选框
 */
void CanttChartScene::drawVerticalAxis(const QStringList &platforms)
{
    // 检查平台列表是否为空
    if (platforms.count() == 0)
    {
        return;
    }

    // 获取场景高度
    const double maxY = this->height();

    // 绘制垂直表头
    int index = 0;
    for (double y = axisStartPoint.y(); y <= maxY; y += verticalGridHeight)
    {
        // 检查是否超出平台数量
        if (index > platforms.count() - 1)
        {
            break;
        }

        // 创建复选框
        QCheckBox *box = new QCheckBox;
        box->setObjectName("PlatformCheckBox");
        // 设置复选框样式
        box->setStyleSheet("#PlatformCheckBox {"
                           "color: rgb(205, 218, 235);"
                           "background-color: rgb(43, 48, 54);"
                           "}"
                           "#PlatformCheckBox::indicator:unchecked {"
                           "border-image: url(:/img/checkbox/timebar-show.png) 0 0 0 0 stretch;"
                           "}"
                           "#PlatformCheckBox::indicator:checked {"
                           "border-image: url(:/img/checkbox/timebar-hide.png) 0 0 0 0 stretch;"
                           "}");
        // 连接复选框点击信号
        connect(box, &QCheckBox::clicked, [=](bool checked) {
            auto list = m_plaformTimeBarHash.values(box->text());

            if (checked)
            {
                foreach (QGraphicsItem *item, list)
                {
                    item->hide();
                }
            }
            else
            {
                foreach (QGraphicsItem *item, list)
                {
                    item->show();
                }
            }
        });
        // 设置复选框文本
        box->setText(platforms.at(index));
        // 创建图形代理部件
        QGraphicsProxyWidget *proxy = addWidget(box);
        // 设置鼠标指针
        proxy->setCursor(QCursor(Qt::PointingHandCursor));
        // 设置位置
        proxy->setPos(QPoint(axisStartPoint.x(), y) + platformHeaderOffset);
        // 保存平台起始Y坐标
        m_platformStartYHash.insert(platforms.at(index), y);
        index++;
    }
}

/**
 * @brief 添加计划时间条
 * @param platform 平台名称
 * @param start 开始时间
 * @param end 结束时间
 * @return 返回创建的时间条项
 * @details 创建计划时间条并添加到场景中
 */
CanttTimeBarItem *CanttChartScene::addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
{
    // 检查平台是否存在
    if (!m_platformStartYHash.keys().contains(platform))
    {
        return nullptr;
    }

    // 添加到缓存
    auto pair = qMakePair(start, end);
    m_planTimeBarTemp.insert(platform, pair);


    // 绘制时间条图形项
    CanttTimeBarItem *item = new CanttTimeBarItem(start, end, CanttTimeBarItem::PlanTime, m_perPixelHMsecs);

    // 计算位置
    double x = m_firstTimeBarStartX + (start.toMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch()) / m_perPixelHMsecs;
    double y = m_platformStartYHash.value(platform) + 3;

    // 添加到场景并设置位置
    addItem(item);
    item->setPos(x, y);

    // 保存到哈希表
    m_plaformTimeBarHash.insert(platform, item);

    return item;
}

/**
 * @brief 添加实际时间条
 * @param platform 平台名称
 * @param start 开始时间
 * @param end 结束时间
 * @return 返回创建的时间条项
 * @details 创建实际时间条并添加到场景中
 */
CanttTimeBarItem *CanttChartScene::addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
{
    // 检查平台是否存在
    if (!m_platformStartYHash.keys().contains(platform))
    {
        return nullptr;
    }

    // 添加到缓存
    auto pair = qMakePair(start, end);
    m_realTimeBarTemp.insert(platform, pair);


    //绘制时间条图形项
    CanttTimeBarItem *item = new CanttTimeBarItem(start, end, CanttTimeBarItem::RealTime, m_perPixelHMsecs);

    double x = m_firstTimeBarStartX + (start.toMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch()) / m_perPixelHMsecs;
    double y = m_platformStartYHash.value(platform) + canttTimeBarHeight + 6;

    addItem(item);
    item->setPos(x, y);

    m_plaformTimeBarHash.insert(platform, item);

    return item;
}

/**
 * @brief 设置时间步长值
 * @param time 时间步长值
 * @details 更新时间步长并重新计算每像素对应的毫秒数
 *          注释掉的代码显示了时间步长更新后更新坐标轴的逻辑
 */
void CanttChartScene::setStepTimeValue(const QTime &time)
{
    m_stepTimeValue = time;
    m_perPixelHMsecs =  m_stepTimeValue.msecsSinceStartOfDay() / (double)horizontalGridWidth;

#if 0

    //时间步长更新后需要更新坐标轴
    if (m_startDateTime.isNull() || m_endDateTime.isNull() || 0 == m_platforms.count())
    {
        return;
    }
    setAxisRange(m_startDateTime, m_endDateTime, m_platforms);
#endif

}

/**
 * @brief 绘制网格线
 * @details 绘制水平和垂直网格线，包括第一条垂直网格线、其他垂直网格线和水平网格线
 */
void CanttChartScene::drawGridLines()
{
    const double maxY = this->height();
    const double maxX = m_firstTimeBarStartX + m_columnCount * horizontalGridWidth;

    //绘制第一条水平网格线
    QGraphicsLineItem *item = new QGraphicsLineItem(axisStartPoint.x(), axisStartPoint.y(), axisStartPoint.x(), maxY);
    item->setPen(QPen(gridLineColor));
    item->setZValue(std::numeric_limits<int>::min());
    addItem(item);

    //绘制水平网格线
    for (double x = axisStartPoint.x() + firstHorizantalGridWidth; x <= maxX; x += horizontalGridWidth)
    {
        QGraphicsLineItem *item = new QGraphicsLineItem(x, axisStartPoint.y(), x, maxY);
        item->setPen(QPen(gridLineColor));
        item->setZValue(std::numeric_limits<int>::min());
        addItem(item);
    }

    //绘制垂直网格线
    for (double y = axisStartPoint.y(); y <= maxY; y += verticalGridHeight)
    {
        QGraphicsLineItem *item = new QGraphicsLineItem(axisStartPoint.x(), y, maxX, y);
        item->setPen(QPen(gridLineColor));
        item->setZValue(std::numeric_limits<int>::min());
        addItem(item);
    }
}

